package org.springframework.aop.framework.autoproxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.Order;

import java.util.List;

/**
 * 切面的顺序 @Order
 */
public class A17_2 {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(MyAspect.class);
        context.registerBean(MyAdvisor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class);
        context.refresh();


        //AnnotationAwareAspectJAutoProxyCreator也是一个BeanPostProcessor
        AnnotationAwareAspectJAutoProxyCreator creator =
                context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
        /**
         * 为了进一步了解了解AOP中匹配Advisor的流程，我们想手动调用AnnotationAwareAspectJAutoProxyCreator中
         * 的findEligibleAdvisors.但这个方法是protected的，我们想要调用，有几个方法 1.继承这个类 2.反射 3.类放
         * 在与AnnotationAwareAspectJAutoProxyCreator同一个包下。这里第3中最为简单，故采用第3种
         */

        /**
         * findEligibleAdvisors:
         * 见名知意，即为目标类查找是否有适合的Advisor。有的话自然表示该Target需要增强
         */
        List<Advisor> advisors = creator.findEligibleAdvisors(Target1.class, "target1");
        for (Advisor advisor : advisors) {
            System.out.println(advisor);
        }

        /**
         * wrapIfNecessary:
         * 内部调用了findEligibleAdvisors，如果返回不为null，表示需要代理，则会为Target创建代理
         *
         */
        Object o1 = creator.wrapIfNecessary(new Target1(), "target1", "target1");
        Object o2 = creator.wrapIfNecessary(new Target2(), "target2", "target2");
        System.out.println(o1.getClass());
        System.out.println(o2.getClass());
        ((Target1) o1).foo();


    }

    static class Target1 {
        public void foo() {
            System.out.println("target1 foo");
        }
    }

    static class Target2 {
        public void bar() {
            System.out.println("target2 bar");
        }
    }

    //通过@Order来指定切面的执行顺序
    @Order(2)
    @Aspect
    static class MyAspect{

        @Before("execution(* foo())")
        public void before(){
            System.out.println("before...");
        }

        @After("execution(* foo())")
        public void after(){
            System.out.println("after...");
        }
    }

    @Configuration
    static class MyAdvisor{

        @Bean
        public Advisor advisor(MethodInterceptor methodInterceptor){
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            advisor.setPointcut(pointcut);
            advisor.setAdvice(methodInterceptor);
            advisor.setOrder(1);  //设置切面的顺序
            return advisor;
        }

        @Bean
        public MethodInterceptor methodInterceptor(){
            return new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    System.out.println("methodInterceptor before...");
                    Object result = invocation.proceed();
                    System.out.println("methodInterceptor after...");
                    return result;
                }
            };
        }
    }
}
